Простая. Человеческая. Интерполяция.

Слово страшное а алгоритм смешной

Sovka Ivanov
6 min readJun 10, 2019
для заголовочка.

Так блять. Если хочешь хорошо въезжать в материал, то читай статью с ручкой и листочком, и все формулы выводи сам, желательно медленно и два раза. Не решай ничего в голове, ебашь смело прямо в тетрадь: “А! ИКС! ПЛЮС БЭ!”

Погнали на примере разбираться. Вот ниже бегут циферки, всё туда-сюда сортируется, как это сделать? Ручной вариант даже не рассматривай, потому что первая же маленькая правка разорвёт тебе жопу. В кратер.

аешный проект с местными гифками в конце

Тут можно либо генерить кифреймы, либо симулировать их. Второй вариант более динамичный (рантаймовый), так что буду симулировать. Надо узнать как кифреймы работают внутри, и там ни хера сложного, вот поясняющая гифка.

пока time бежит от t1 до t2, value синхронно с ним меняется от v1 до v2.

Чтоб упростить задачу, пускай t1 = 0 и t2 = 1. Нужно этот промежуток типа замапить на [v1, v2]. Для начала логично его смасштабить до требуемого размера. Исходный размер 1, конечный размер v2 - v1, видимо достаточно просто умножить на конечный размер. Теперь полученный промежуток надо подвинуть, чтоб он совпал с конечным, это просто добавить v1.

value = time * (v2 — v1) + v1; time [0, 1]

из школы наверно помнишь линейную функцию y = ax + b. Это она.

Сначала масштаб, потом оффсет, хуль тут непонятного.

Такая функция есть почти во всех софтах, может называться lerp\linear\fit\хуйзнает. Чаще всего я встречал lerp. Но тебе нужна функция чуть посложнее, чтоб начальный промежуток был любой, а не только [0, 1]. Можно замутить перевод начального промежутка в [0,1], а затем [0, 1] в конечный, и это довольно просто. Перевести в [0, 1] — это как перевести из него, только полностью наоборот, т.е. сначала убрать к хуям оффсет, затем скукожить до размера 1.

t01 = (time - t1) / (t2 - t1)

Ну и всё, есть формула от чего угодно к [0, 1], и есть формула от [0, 1] к чему угодно, ща как объеденю их, охуеешь там.

value = (time - t1) / (t2 - t1) * (v2 - v1) + v1

Приглядись и узри, что t1 ≠ t2, иначе деление страшное на ноль гроб гроб кладбище пидор.

Ну вот, есть два времени, два значения и ровная инструкция, чо с этим всем делать. Кейфрейм в простейшей форме представляет из себя два числа — время и значение. Просто два обоссанных числа, ничего более. Линейная интерполяция представляет из себя вон ту формулу, четыре сложения и по одной штуке умножения и деления, никакой сверхъестественной параши. И всё ёпта, ты уже готов симулить кифреймы выраженцем в афтере, петоном в синьке, сиплюсплюсом в анриле, да хоть мелом на асфальте ебашь — алгоритм будет работать в голове читающего. Потому что алгоритму похуй где работать (в отличие от тебя). Возвращаюсь к тем бегункам, ниже выраженец скрином. Там есть костыль, связанный с тем, что в афтере нельзя хранить переменные между кадрами. Т.е. время изменения value нельзя просто взять и схоронить, его придётся постоянно искать прокатываясь циклом по кадрам назад. Как только нашёл — записал время в t1, а предыдущее значение в v1. К t1 прибавил время анимации, получил t2, нынешнее значение записал в v2. Это все необходимые переменные для формулы.

да хуй знает, вроде всё ясно.

Давай теперь покажу тебе кое-что пожощще. Нелинейную интерполяцию.

можешь рассматривать это как график значения от времени.

баяс пока трогать не буду, ну его нахой. Пускай он по умолчанию в серединке. График получается симметричным относительно серединки, так что можно рассмотреть только половину, потом отзеркалить её как суку просто.

половинка графика

Беглый анализ на глаз: пересекается с исходной прямой в 2 точках, начало жмётся к плинтусу, конец ебашит вверх. Т.е. рост функции ускоряется.

Ебать, да это ж парабола!

Пускай начальный и конечный промежутки будут [0, 1] оба. Сразу нужно разделить на 2 половинки: до серединки, и после. То, что до серединки, [0, 0.5], лерпануть (lerp) в [0, 1]. Ну это просто умножить на 2. Затем возвести в любую степень, начало промежутка останется нулём, конец промежутка останется единицей, а всё что между начнёт кривиться по-парабольски. Чем больше степень, тем лютее кривизна. Ну и т.к. это была половина начального промежутка, то надо сжать обратно до половины, т.е. разделить на 2 обратно.

if (x < 0.5)  { (x * 2)ⁿ / 2 }

Охуенно, с первой половиной ты разобрался (надеюсь). Вторая точно так же, но зеркально. Значит сначала тоже лерпануть её в [0, 1], и инвертнуть, т.е. вычесть из единицы. Получится [1, 0].

1 - (x - 0.5) * 2 = 1 - 2x + 1 = 2 - 2x = (1- x) * 2

— итоговая формула отзеркаленной и лерпнутой. Это то, что нужно возвести в степень. И после возведения вертать всё взад в [0.5, 1]

1 - ((1 - x) * 2)ⁿ / 2

Общая залупа такая получилась:

if (x < 0.5) { (x * 2)ⁿ / 2 }else { 1 - ((1 - x) * 2)ⁿ / 2 }

Это уже чуть труднее и нелинейнее, так что для закрепления рекомендую повторить всё на бумаге в жало. И хорошенько до деталек понять, чо здесь как работает, не стесняйся строить графики и врубаться, какая операция какую роль играет.

Ну осталось добавить баяс (смещение). Если выполнил рекомендацию выше, то сможешь добавить его самостоятельно. Там прост серёдку выбирай не 0.5, а что-то другое, значение из слайдера например. Энивей в проекте ниже всё есть.

А теперь покажу, где интерполяция применяется. Если ты хотел недооценить её мощь, то возможно тебе придётся охуеть.

Твой любимый виггл — лерп равных промежутков времени в рандомные значения. Здесь я добавил недавний степенной изинг, смотри как плавно вигглится.

Вот это происходит на каждом кадре при рендоре каждого полигона на видяхе. Здесь билинейная интерполяция, она делается на плоскости между тремя точкамии. Вот как делается: пусть это полигон в координатах моника,уже двумерный. В 3 пикселях, в которых расположены вершины полигона, цвет известен, это цвет вершины заданный юзером или чем-то ещё, видяха рендорит этот цвет. А цвет в каждом пикселе внутри этого полика видяха вычисляет как раз интерполяцией между этими тремя вершинами. Про то, как видяха прошаривает, какому пикселю какой цвет назначить, я кратко описал здесь. Как работает билинейная интерполяция — в проекте.

Кривые Безье внутри есть множественная интерполяция, каскадная штоле хз. Я про это уже писал статейку, читани подробно. Если всё поймёшь там, то прошаришь, как симулить кифреймы с безьешными изингами здесь.

Эти примеры являются чистым интерполяцьюоном, в них нет ничего кроме него. Вот так, вроде простейшая шелуха, а такая фундаментальная, что без неё наших с тобой профессий вообще не существовало бы.

проектик

я

--

--

Sovka Ivanov

Папкин математик, мамкин программист, дизайнер папиной подруги.